define(function() {
    // 查询指定节点的子节点
    function findNodeChildren(targetNode, nodes, lines) {
        let res = lines.filter(line => line.nodeId === targetNode.id)
                    .map(line => nodes.find(tn => tn.id === line.nextNodeId));
        // 去重
        let nids = res.map(node => node.id);
        let nnids = Array.from(new Set(nids));
        let nres = nnids.map(nid => res.find(nn => nn.id === nid));
        return nres;
    }

    // 节点深度信息统计
    function generateDeepFirstTraversalMetaData (metaDatas, startNode, deep, nodes, lines) {
        metaDatas.push({
            deep: deep, 
            node: startNode
        })
        // console.log(`查询【${node.name}】子节点...`);
        let children = findNodeChildren(startNode, nodes, lines);

        if(Array.isArray(children) && children.length > 0) {
            // 排除父辈已经遍历过的节点
            children = children.filter(child => metaDatas.findIndex(nn => nn.node.id === child.id) < 0);
            // 继续遍历剩余有关联的步骤
            children.forEach(child => {
                // 排除由于深度查询已经遍历过的子节点
                if(metaDatas.findIndex(nn => nn.node.id === child.id) < 0) {
                    generateDeepFirstTraversalMetaData(metaDatas, child, deep + 1, nodes, lines);
                }
            })
        }
    }

    function findDefaultFirstNode(rootId, nodes) {
        if(!!rootId && rootId.length > 0) {
            return nodes.find(nn => nn.id === rootId);
        }
        return null;
    }

    // 查找子节点, 不去重
    let findChildrenNoHeavy = (node, nodes, lines) => {
        let res = lines.filter(line => line.nodeId === node.id)
                        .map(line => nodes.find(tn => tn.id === line.nextNodeId));
        return res;
    }

    /**
     * 生成节点模板
     * @param 传递 node 或者 nodeId
     */
    function generateSingleNodePattern(nodeOrNodeId, nodes, lines) {
        let node = typeof nodeOrNodeId === 'object' ? nodeOrNodeId : nodes.find(nn => nn.id === nodeOrNodeId);
        let clen = findChildrenNoHeavy(node, nodes, lines).length;
        let pattern = clen > 1 ? `${node.id}{"${repSign(node.name)}"}` : `${node.id}("${repSign(node.name)}")`;
        return pattern;
    }

    // 替换中文标点符号, 防止模板解析过程出错
    function repSign(s) {
        s = s.replace(/，/g, ',');
        s = s.replace(/。/g, '.');
        s = s.replace(/？/g, '?');
        s = s.replace(/！/g, '!');
        return s;
    }

    function generateGraphDefinition(rootId, nodes, lines, globalEventHandlerId, layout) {
        if(nodes.length <= 0 && lines.length <= 0) {
            return ['graph LR', '空'].join('\n');
        }

        var firstNode = findDefaultFirstNode(rootId, nodes);
        // 没有配置，则自动判断
        if(firstNode == null) {
            // 查询根节点, 不一定是流程根节点, 这里指的逻辑根节点
            firstNode = nodes.find(node => {
                // 有关联关系, 但是没有任何关联关系指向该步骤
                if(lines.findIndex(line => line.nodeId === node.id) >= 0
                    && lines.findIndex(line => line.nextNodeId === node.id) < 0) {
                    return true;
                }
                return false;
            });
        }

        // 为 Node 节点排序, 使生成的节点排序位置更加合理
        if(!!firstNode) {
            let treeNodeMetaData = [];
            // 记录深度
            generateDeepFirstTraversalMetaData(treeNodeMetaData, firstNode, 1, nodes, lines);
            // 广度优先遍历
            let deep = 1;
            // 保存已从首节点开始遍历, 关联的节点
            let newNodes = [];
            
            // 最多查询深度为 100
            while(deep <= 100) {
                let tArr = treeNodeMetaData.filter(meta => meta.deep === deep).map(meta => meta.node);
                
                if(tArr.length <= 0) {
                    break;
                }

                deep++;
                newNodes = newNodes.concat(tArr);
            }
            
            // 查询剩余
            let surPlusNodes = nodes.filter(node => newNodes.findIndex(tn => tn.id === node.id) < 0);
            nodes = [];
            newNodes.concat(surPlusNodes).forEach(node => nodes.push(node));
        }

        let tArr = ['graph ' + (layout||'TB')];

        // 出口节点数量
        let exitNodeSize = 0;

        nodes.forEach((node, index) => {
            if(index === 0) {
                tArr.push(`tzstart((开始))-->${generateSingleNodePattern(node, nodes, lines)}`);
            }

            // 查询 Node 连接的节点名称
            let nArr = lines.filter(line => line.nodeId === node.id)
                            .map(line => {
                                return {
                                    text : line.desc,
                                    toId : line.nextNodeId
                                }
                            })
                            .map(meta => {
                                let startText = generateSingleNodePattern(node, nodes, lines);
                                let endText = generateSingleNodePattern(meta.toId, nodes, lines);
                                if(!!meta.text) {
                                    return repSign(`${startText}-->|${meta.text}|${endText}`)
                                }
                                return repSign(`${startText}-->${endText}`)
                            });

            if(findNodeChildren(node, nodes, lines).length <= 0) {
                exitNodeSize++;
                tArr.push(repSign(`${node.id}(${node.name})-->tzend((结束))`));
            }
            
            // 该节点尚未建立关联
            if(nArr.length <= 0)  {
                nArr.push(`${node.id}(${node.name})`);
            } else {
                tArr = tArr.concat(nArr);
            }          
        });

        // 添加节点点击事件定义
        nodes.forEach(node => {
            tArr.push(`click ${node.id} ${globalEventHandlerId} "点击"`);
        });

        // 为节点添加 style 样式
        if(!!firstNode) {
            tArr.push(`style tzstart fill:#f9f,stroke:#333,stroke-width:4px;`);
            if(exitNodeSize > 0) {
                tArr.push(`style tzend fill:#ccf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5`);
            }
        }

        // 为每个步骤添加 class(step-wrapper)
        nodes.forEach(node => {
            tArr.push(`class ${node.id} step-wrapper`);
        });

        let pattern = [tArr.shift(), tArr.join(';\r\n')].join('\r\n');
        // console.log(pattern);

        return pattern;
    }

    return generateGraphDefinition;
});